
#include "StdAfx.h"
#include ".\xmlnode.h"

//////////////////////////////////////////////////////////////////////////
#ifndef _tstof
#ifdef _UNICODE

double __cdecl _tstof( const wchar_t *ptr )
{
    CHAR astring[20];
    WideCharToMultiByte( CP_ACP, 0, ptr, -1, astring, 20, NULL, NULL);
    return atof(astring);
}

#else
#define _tstof atof
#endif
#endif
//////////////////////////////////////////////////////////////////////////

BOOL CXmlNode::_GetValue(CString & strValue OUT)
{
    ASSERT( m_pNode != NULL );
    
    HRESULT hr = S_OK;
    try
    {
        if( HasChildren() )
        {
            ASSERT( FALSE );
            return FALSE;
        }
        
        BSTR bstr = NULL;
        hr = m_pNode->get_text( &bstr );
        ASSERT( SUCCEEDED(hr) ); 
        strValue = (LPCTSTR)_bstr_t( bstr, true);
        
        if( bstr != NULL )
        {
            SysFreeString(bstr);
            bstr = NULL;
        }
    }
    catch ( _com_error e )
    {
        TRACE( _T("CXmlNode::_GetValue exception: %s\n"), e.ErrorMessage());
        ASSERT( FALSE );
        return FALSE;
    }
    
    return SUCCEEDED(hr);
}

BOOL CXmlNode:: _SetValue(CString & strValue IN)
{
    ASSERT( m_pNode != NULL );
    
    HRESULT hr = S_OK;
    
    try
    {
        if( HasChildren() )
        {
            ASSERT( FALSE );
            return FALSE;
        }
        
        hr = m_pNode->put_text( CComBSTR(strValue) );
        ASSERT( SUCCEEDED(hr) );
    }
    catch ( _com_error e )
    {
        TRACE( _T("CXmlNode::_SetValue exception: %s\n"), e.ErrorMessage());
        ASSERT( FALSE );
        return FALSE;
    }
    return SUCCEEDED(hr);
}

BOOL CXmlNode::_GetAttribute( CString & strName IN, CString & strValue OUT)
{
    ASSERT( m_pNode != NULL );
    
    HRESULT hr = S_OK;
    
    try
    {
        MSXML2::IXMLDOMNamedNodeMapPtr pIXMLDOMNamedNodeMap = NULL;
        hr = m_pNode->get_attributes(&pIXMLDOMNamedNodeMap);
        if( !SUCCEEDED(hr) )
        {
            ASSERT( FALSE );
            return FALSE;
        }
        
        MSXML2::IXMLDOMNodePtr pIXMLDOMNode = NULL;
        pIXMLDOMNode = pIXMLDOMNamedNodeMap->getNamedItem( _bstr_t(strName) );
        
        if( pIXMLDOMNode == NULL )
        {
            strValue.Empty();
        }
        else
        {
            VARIANT varValue;
            hr = pIXMLDOMNode->get_nodeValue(&varValue);
            if( !SUCCEEDED(hr) )
            {
                ASSERT( FALSE );
                return FALSE;
            }
            
            strValue = (LPCTSTR)(_bstr_t)varValue;
        }
        
        RELEASE_PTR(pIXMLDOMNode);
        RELEASE_PTR(pIXMLDOMNamedNodeMap);
    }
    catch ( _com_error e )
    {
        TRACE( _T("CXmlNode::_GetAttribute exception: %s\n"), e.ErrorMessage());
        ASSERT( FALSE );
        return FALSE;
    }
    
    return TRUE;
}

BOOL CXmlNode::_SetAttribute( CString & strName, CString & strValue IN)
{
    ASSERT( m_pNode != NULL );
    
    HRESULT hr = S_OK;
    try
    {
        MSXML2::IXMLDOMElementPtr pElement = NULL;
        pElement = static_cast<MSXML2::IXMLDOMElementPtr> (m_pNode);
        hr = pElement->setAttribute( (_bstr_t)CComBSTR(strName), _variant_t((LPCTSTR)strValue) );
        RELEASE_PTR(pElement);
    }
    catch ( _com_error e )
    {
        TRACE( _T("CXmlNode::_SetAttribute exception: %s\n"), e.ErrorMessage());
        ASSERT( FALSE );
        return FALSE;
    }
    
    return SUCCEEDED(hr);
}

CXmlNode::CXmlNode( MSXML2::IXMLDOMNodePtr pNode IN)
{
    m_pNode = pNode;
}

CXmlNode::CXmlNode(void)
{
    m_pNode = NULL; 
}

CXmlNode::CXmlNode( CXmlNode & refNode IN)
{
    m_pNode = refNode.m_pNode;
}

CXmlNode::~CXmlNode(void)
{
    RELEASE_PTR(m_pNode);
}

void CXmlNode::Release(void)
{
    RELEASE_PTR(m_pNode);
}

CXmlNodePtr CXmlNode::operator = ( CXmlNodePtr pNode IN)
{
    RELEASE_PTR(m_pNode);
    
    m_pNode = pNode->m_pNode;
    return pNode;
}

CXmlNode & CXmlNode::operator = ( CXmlNode & refNode IN)
{
    RELEASE_PTR(m_pNode);
    
    m_pNode = refNode.m_pNode;
    return (*this);
}

BOOL CXmlNode::IsNull(void)
{
    return m_pNode == NULL;
}

CXmlNodePtr CXmlNode::GetChild( CString strName, BOOL bBuildIfNotExist /* = TRUE */)
{
    ASSERT( m_pNode != NULL );
    
    CXmlNodePtr pChild( new CXmlNode() );
    
    try
    {
        MSXML2::IXMLDOMNodePtr pChildNode = NULL;
        pChildNode = m_pNode->selectSingleNode(_bstr_t((LPCTSTR)strName));
        
        if( pChildNode == NULL && bBuildIfNotExist )
        {
            MSXML2::IXMLDOMDocumentPtr pDoc = NULL;
            HRESULT hr = m_pNode->get_ownerDocument(&pDoc);
            ASSERT( SUCCEEDED(hr) );
            
            pChildNode = pDoc->createElement( _bstr_t(strName) );
            ASSERT( pChildNode != NULL );
            
            m_pNode->appendChild(pChildNode);
            
            RELEASE_PTR(pDoc);
        }
        
        pChild->m_pNode = pChildNode; 
        RELEASE_PTR(pChildNode);
    }
    catch ( _com_error e )
    {
        TRACE( _T("CXmlNode::GetChildexception: %s\n"), e.ErrorMessage());
        ASSERT( FALSE );
    }
    
    return pChild;
}

CXmlNodePtr CXmlNode::NewChild( CString strName )
{
    ASSERT( m_pNode != NULL );
    
    CXmlNodePtr pChild( new CXmlNode() );
    
    try
    {
        MSXML2::IXMLDOMDocumentPtr pDoc = NULL;
        HRESULT hr = m_pNode->get_ownerDocument(&pDoc);
        ASSERT( SUCCEEDED(hr) );
        
        MSXML2::IXMLDOMNodePtr pChildNode = NULL;
        pChildNode = pDoc->createElement( _bstr_t(strName) );
        ASSERT( pChildNode != NULL );
        RELEASE_PTR(pDoc);
        
        m_pNode->appendChild(pChildNode);
        pChild->m_pNode = pChildNode;
        RELEASE_PTR(pChildNode);
    }
    catch ( _com_error e )
    {
        TRACE( _T("CXmlNode::NewChild exception: %s\n"), e.ErrorMessage());
        ASSERT( FALSE );
    }
    return pChild; 
}

void CXmlNode::AddChild( CXmlNodePtr & pChildNode)
{
    ASSERT( m_pNode != NULL );
    
    try
    {
        m_pNode->appendChild( pChildNode->m_pNode );
    }
    catch ( _com_error e )
    {
        TRACE( _T("CXmlNode::AddChild exception: %s\n"), e.ErrorMessage());
        ASSERT( FALSE );
    }
}

void CXmlNode::AddChild( CXmlNode & refChildNode)
{
    ASSERT( m_pNode != NULL );
    
    try
    {
        m_pNode->appendChild( refChildNode.m_pNode );
    }
    catch ( _com_error e )
    {
        TRACE( _T("CXmlNode::AddChild exception: %s\n"), e.ErrorMessage());
        ASSERT( FALSE );
    }
}

CXmlNodePtr CXmlNode::GetParent(void)
{
    ASSERT( m_pNode != NULL );
    
    CXmlNodePtr pParent( new CXmlNode() );
    
    try
    {
        pParent->m_pNode = m_pNode->GetparentNode();
    }
    catch ( _com_error e )
    {
        TRACE( _T("CXmlNode::GetParent exception: %s\n"), e.ErrorMessage());
        ASSERT( FALSE );
    }
    return pParent;
}

CString CXmlNode::GetName(void)
{
    ASSERT( m_pNode != NULL );
    
    CString strRet;
    
    try
    {
        BSTR bstr = NULL;
        HRESULT hr = m_pNode->get_nodeName(&bstr);
        ASSERT( SUCCEEDED(hr) ); 
        strRet = (LPCTSTR)_bstr_t( bstr, true);
        
        if( bstr != NULL )
        {
            SysFreeString(bstr);
            bstr = NULL;
        }
    }
    catch ( _com_error e )
    {
        TRACE( _T("CXmlNode::GetName exception: %s\n"), e.ErrorMessage());
        ASSERT( FALSE );
    }
    
    return strRet;
}

BOOL CXmlNode::RemoveAttribute( CString strName IN )
{
    ASSERT( m_pNode != NULL );
    
    HRESULT hr = S_OK;
    
    try
    {
        MSXML2::IXMLDOMNamedNodeMapPtr pIXMLDOMNamedNodeMap = NULL;
        hr = m_pNode->get_attributes(&pIXMLDOMNamedNodeMap);
        ASSERT( SUCCEEDED(hr) );
        
        if( SUCCEEDED(hr) )
            pIXMLDOMNamedNodeMap->removeNamedItem( _bstr_t(strName) );
        ASSERT( SUCCEEDED(hr) );
        
        RELEASE_PTR(pIXMLDOMNamedNodeMap);
    }
    catch ( _com_error e )
    {
        TRACE( _T("CXmlNode::RemoveAttribute exception: %s\n"), e.ErrorMessage());
        ASSERT( FALSE );
        return FALSE;
    }
    
    
    return SUCCEEDED(hr);
}

BOOL CXmlNode::HasChildren(void)
{
    ASSERT( m_pNode != NULL );
    
    BOOL bHasChildren = FALSE;
    try
    {
        MSXML2::IXMLDOMNodeListPtr pNodeList = NULL;
        pNodeList = m_pNode->selectNodes( _bstr_t("child::*") );
        ASSERT( pNodeList != NULL );
        
        bHasChildren = static_cast<BOOL>(pNodeList->length != 0);
        RELEASE_PTR(pNodeList);
    }
    catch ( _com_error e )
    {
        TRACE( _T("CXmlNode::HasChildren exception: %s\n"), e.ErrorMessage());
        ASSERT( FALSE );
    }
    return bHasChildren;
}

CXmlNode & CXmlNode::Remove(void)
{
    ASSERT( m_pNode != NULL );
    
    try
    {
        HRESULT hr = S_OK;
        MSXML2::IXMLDOMNodePtr pNode = NULL;
        hr = m_pNode->get_parentNode(&pNode);
        ASSERT( SUCCEEDED(hr) );
        
        pNode->removeChild(m_pNode);
    }
    catch ( _com_error e )
    {
        TRACE( _T("CXmlNode::Remove exception: %s\n"), e.ErrorMessage());
        ASSERT( FALSE );
    }
    return (*this);
}

BOOL CXmlNode::RemoveChildren(void)
{
    ASSERT( m_pNode != NULL );
    
    try
    {
        MSXML2::IXMLDOMNodeListPtr pNodeList = NULL;
        pNodeList = m_pNode->selectNodes( _bstr_t("child::*") );
        
        for( int i = 0; i < pNodeList->length; i++)
        {
            m_pNode->removeChild( pNodeList->item[i] );
        }
        
        RELEASE_PTR(pNodeList);
    }
    catch ( _com_error e )
    {
        TRACE( _T("CXmlNode::Remove exception: %s\n"), e.ErrorMessage());
        ASSERT( FALSE );
        return FALSE;
    }
    
    return TRUE;
}

CXmlNodesPtr CXmlNode::GetChildren()
{
    ASSERT( m_pNode != NULL );
    
    CXmlNodesPtr pNodes ( new CXmlNodes() );
    try
    {
        MSXML2::IXMLDOMNodeListPtr pNodeList = NULL;
        pNodeList = m_pNode->selectNodes( _bstr_t("child::*") );
        
        pNodes->m_pNodeList = pNodeList;
        RELEASE_PTR(pNodeList);
    }
    catch ( _com_error e )
    {
        TRACE( _T("CXmlNode::GetChildren exception: %s\n"), e.ErrorMessage());
        ASSERT( FALSE );
    }
    return pNodes;
}

CXmlNodePtr CXmlNode::SelectSingleNode(LPCTSTR lpszPath)
{
    ASSERT( m_pNode != NULL );
    
    CXmlNodePtr pNode ( new CXmlNode() );
    
    try
    {
        MSXML2::IXMLDOMNodePtr pItem = NULL;
        pItem = m_pNode->selectSingleNode( _bstr_t(lpszPath) );
        
        pNode->m_pNode = pItem;
        RELEASE_PTR(pItem);
    }
    catch ( _com_error e )
    {
        TRACE( _T("CXmlNode::SelectSingleNode exception: %s\n"), e.ErrorMessage());
        ASSERT( FALSE );
    }
    
    return pNode;
}

CXmlNodesPtr CXmlNode::SelectNodes(LPCTSTR lpszPath)
{
    ASSERT( m_pNode != NULL );
    
    CXmlNodesPtr pNodes ( new CXmlNodes() );
    try
    {
        MSXML2::IXMLDOMNodeListPtr pNodeList = NULL;
        pNodeList = m_pNode->selectNodes( _bstr_t(lpszPath) );
        
        pNodes->m_pNodeList = pNodeList;
        RELEASE_PTR(pNodeList);
    }
    catch ( _com_error e )
    {
        TRACE( _T("CXmlNode::SelectNodes exception:%s\n"), e.ErrorMessage());
        ASSERT( FALSE );
    }
    
    return pNodes;
}

CString CXmlNode::GetValue(LPCTSTR lpszValue /* = NULL */ )
{
    CString strValue;
    _GetValue(strValue);
    
    if( strValue.IsEmpty() &&
        lpszValue != NULL )
    {
        strValue = lpszValue;
        _SetValue(strValue);
    }
    
    return strValue;
}


bool CXmlNode::GetValue( bool bDefault )
{
    CString strValue;
    _GetValue(strValue);
    
    if( strValue.CompareNoCase(_T("1")) == 0 )
    {
        return TRUE;
    }
    else if( strValue.CompareNoCase(_T("0")) == 0 )
    {
        return FALSE;
    }
    else
    {
        strValue = bDefault ? "1" : "0";
        _SetValue(strValue);
        return bDefault;
    } 
}


int CXmlNode::GetValue( int nDefault )
{
    CString strValue;
    _GetValue(strValue);
    
    if( strValue.IsEmpty() )
    {
        strValue.Format( _T("%d"), nDefault);
        _SetValue(strValue);
    }
    
    return _ttoi(strValue);
}

float CXmlNode::GetValue( float fDefault )
{
    CString strValue;
    _GetValue(strValue);
    
    if( strValue.IsEmpty() )
    {
        strValue.Format( _T("%f"), fDefault);
        _SetValue(strValue);
    }
    
    return static_cast<float> (_tstof(strValue));
}

double CXmlNode::GetValue( double dDefault )
{
    CString strValue;
    _GetValue(strValue);
    
    if( strValue.IsEmpty() )
    {
        strValue.Format( _T("%.12f"), dDefault);
        _SetValue(strValue);
    }
    
    return _tstof(strValue);
}

BOOL CXmlNode::SetValue( LPCTSTR lpszValue )
{
    CString strValue(lpszValue);
    return _SetValue(strValue);
}

BOOL CXmlNode::SetValue( bool bValue )
{
    CString strValue;
    strValue = bValue ? _T("1") : _T("0");
    
    return _SetValue(strValue);
}

BOOL CXmlNode::SetValue( int nValue )
{
    CString strValue;
    strValue.Format( _T("%d"), nValue);
    
    return _SetValue(strValue);
}

BOOL CXmlNode::SetValue( float fValue )
{
    CString strValue;
    strValue.Format( _T("%f"), fValue);
    
    return _SetValue(strValue);
}

BOOL CXmlNode::SetValue( double dValue )
{
    CString strValue;
    strValue.Format( _T("%.12f"), dValue);
    
    return _SetValue(strValue);
}

CString CXmlNode::GetAttribute( CString strName, LPCTSTR lpszDefault /* = NULL */)
{
    CString strValue;
    _GetAttribute( strName, strValue);
    
    if( strValue.IsEmpty() &&
        lpszDefault != NULL )
    {
        strValue = lpszDefault;
        _SetAttribute( strName, strValue);
    }
    return strValue;
}

bool CXmlNode::GetAttribute( CString strName, bool bDefault)
{
    CString strValue;
    _GetAttribute( strName, strValue);
    
    if( strValue.CompareNoCase(_T("1")) == 0 )
    {
        return TRUE;
    }
    else if( strValue.CompareNoCase(_T("0")) == 0 )
    {
        return FALSE;
    }
    else
    {
        strValue = bDefault ? _T("1") : _T("0");
        _SetAttribute( strName, strValue);
        return bDefault;
    } 
}

int CXmlNode::GetAttribute( CString strName, int nDefault)
{
    CString strValue;
    _GetAttribute( strName, strValue);
    
    if( strValue.IsEmpty() )
    {
        strValue.Format( _T("%d"), nDefault);
        _SetAttribute( strName, strValue);
    }
    
    return _ttoi(strValue);
}

float CXmlNode::GetAttribute( CString strName, float fDefault)
{
    CString strValue;
    _GetAttribute( strName, strValue);
    
    if( strValue.IsEmpty() )
    {
        strValue.Format( _T("%f"), fDefault);
        _SetAttribute( strName, strValue);
    }
    
    return static_cast<float>(_tstof(strValue));
}

double CXmlNode::GetAttribute( CString strName, double dDefault)
{
    CString strValue;
    _GetAttribute( strName, strValue);
    
    if( strValue.IsEmpty() )
    {
        strValue.Format( _T("%.12f"), dDefault);
        _SetAttribute( strName, strValue);
    }
    
    return _tstof(strValue);
}

BOOL CXmlNode::SetAttribute( CString strName, LPCTSTR lpszValue)
{
    CString strValue;
    strValue = lpszValue;
    
    return _SetAttribute( strName, strValue); 
}

BOOL CXmlNode::SetAttribute( CString strName, bool bValue)
{
    CString strValue;
    strValue = bValue ? _T("1") : _T("0");
    
    return _SetAttribute( strName, strValue); 
}

BOOL CXmlNode::SetAttribute( CString strName, int nValue)
{
    CString strValue;
    strValue.Format( _T("%d"), nValue);
    
    return _SetAttribute( strName, strValue); 
}

BOOL CXmlNode::SetAttribute( CString strName, float fValue)
{
    CString strValue;
    strValue.Format( _T("%f"), fValue);
    
    return _SetAttribute( strName, strValue); 
}

BOOL CXmlNode::SetAttribute( CString strName, double dValue)
{
    CString strValue;
    strValue.Format( _T("%.12f"), dValue);
    
    return _SetAttribute( strName, strValue); 
}